/*
 * Most parts of this file is copied from the original edition.
 *     The page-related parts are obviously architecture-independent.
 * Should consider merging them into a common header in the future.
 */

#ifndef __ARCH_UM_INCLUDE_MEMLAYOUT_H__
#define __ARCH_UM_INCLUDE_MEMLAYOUT_H__

#include <mmu.h>

/* 
 * Memory map of the first process
 *
 *    +-------------------------+
 *	  |                         |
 *	  |       * Inalid *        |
 *	  |                         |
 *	  +-------------------------+ <---------- KERNTOP     \
 *	  |                         |                          \
 *	  |     Physical Memory     |                           KMEMSIZE
 *	  |                         |                          /
 *	  +-------------------------+ <---------- RESERVED_END \
 *	  |        Reserved         |                           RESERVED_SIZE 
 *	  +-------------------------+ <---------- KERNBASE     /
 *
 *
 *
 *
 *
 *
 *
 */

#define KERNBASE           0x10000                       /* this is the lowest address we can map */
#define KMEMSIZE           0x38000000                    /* the maximum amount of physical memory */
#define KERNTOP            (KERNBASE + KMEMSIZE)

#define RESERVED_END       0x100000
#define RESERVED_SIZE      (RESERVED_END - KERNBASE)
#define BOOT_CODE          0xFF000

#define GLOBL_INFO         KERNBASE

#ifndef __ASSEMBLER__

#define E820MAX             20      // number of entries in E820MAP
#define E820_ARM            1       // address range memory
#define E820_ARR            2       // address range reserved

struct E820MAP {
    int nr_map;
    struct {
        uint64_t addr;
        uint64_t size;
        uint32_t type;
    } __attribute__((packed)) map[E820MAX];
};


#define ginfo              ((struct global_info*)GLOBL_INFO)
#define e820map            (ginfo->mem_map)

struct global_info {
	int mem_fd;
	struct E820MAP mem_map;
};

#ifndef __BOOT__

#include <types.h>
#include <atomic.h>
#include <list.h>

/* Basic types for mm. */
typedef uintptr_t pte_t;
typedef uintptr_t pde_t;

/* *
 * struct Page - Page descriptor structures. Each Page describes one
 * physical page. In pmm.h, you can find lots of useful functions
 * that convert Page to other data types, such as phyical address.
 * */
struct Page {
    atomic_t ref;                   // page frame's reference counter
    uint32_t flags;                 // array of flags that describe the status of the page frame
    unsigned int property;          // used in buddy system, stores the order (the X in 2^X) of the continuous memory block
    int zone_num;                   // used in buddy system, the No. of zone which the page belongs to
    list_entry_t page_link;         // free list link
};

/* Flags describing the status of a page frame */
#define PG_reserved					0		// the page descriptor is reserved for kernel or unusable
#define PG_property					1		// the member 'property' is valid
#define PG_slab                     2       // page frame is included in a slab

#define SetPageReserved(page)		set_bit(PG_reserved, &((page)->flags))
#define ClearPageReserved(page)		clear_bit(PG_reserved, &((page)->flags))
#define PageReserved(page)			test_bit(PG_reserved, &((page)->flags))
#define SetPageProperty(page)		set_bit(PG_property, &((page)->flags))
#define ClearPageProperty(page)		clear_bit(PG_property, &((page)->flags))
#define PageProperty(page)			test_bit(PG_property, &((page)->flags))
#define SetPageSlab(page)           set_bit(PG_slab, &((page)->flags))
#define ClearPageSlab(page)         clear_bit(PG_slab, &((page)->flags))
#define PageSlab(page)              test_bit(PG_slab, &((page)->flags))

// convert list entry to page
#define le2page(le, member)					\
	to_struct((le), struct Page, member)

/* free_area_t - maintains a doubly linked list to record free (unused) pages */
typedef struct {
	list_entry_t free_list;			// the list header
	unsigned int nr_free;			// # of free pages in this free list
} free_area_t;

#endif  /* !__ASSEMBLER__ */
#endif  /* !__BOOT__ */

#endif  /* !__ARCH_UM_INCLUDE_MEMLAYOUT_H__ */
